package controllers

import (
    "gouniapp/configs"
	"fmt"
	"time"
	"net/http"
    "strings"
	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	"gorm.io/gorm"
	"gorm.io/gorm/clause"
	"strconv"
	"sort"
)

// 清理未使用的数据表
func Cleanapi(c *gin.Context) {
    // 获取所有注册的表名
    var registeredTables []string
    if err := configs.DB.Model(&configs.FormSchema{}).Pluck("tablename", &registeredTables).Error; err != nil {
        JsonResponse(c, http.StatusInternalServerError, "获取注册表失败", gin.H{"error": err.Error()})
        return
    }
    // 添加保护逻辑：当注册表为空时拒绝删除操作
    if len(registeredTables) == 0 {
        JsonResponse(c, http.StatusBadRequest, "拒绝危险操作：注册表为空时将删除所有系统表", nil)
        return
    }
    // 获取数据库所有表
    m := configs.DB.Migrator()
    allTables, err := m.GetTables()
    if err != nil {
        JsonResponse(c, http.StatusInternalServerError, "获取数据库表失败", gin.H{"error": err.Error()})
        return
    }
    // 过滤出form_开头的表
    systemTables := make([]string, 0)
    for _, t := range allTables {
        if strings.HasPrefix(t, "form_") && t != "form_schemas"{
            systemTables = append(systemTables, t)
        }
    }
    // 创建注册表映射（快速查找）
    registeredMap := make(map[string]struct{})
    for _, t := range registeredTables {
        registeredMap[t] = struct{}{}
    }
    // 找出需要删除的表：表名以form_开头且未在FormSchema注册表中存在
    var deletedTables []string
    for _, table := range systemTables {
        //白名单忽略
        if table == "form_schemas" {
            continue
        }
        if _, exists := registeredMap[table]; !exists {
            // 执行删除操作
            if err := m.DropTable(table); err != nil {
                JsonResponse(c, http.StatusInternalServerError, "删除表失败", gin.H{"table": table, "error": err.Error()})
                return
            }
            deletedTables = append(deletedTables, table)
        }
    }
    JsonResponse(c, http.StatusOK, "清理完成", gin.H{
        "deleted_tables":   deletedTables,
        "deleted_count":    len(deletedTables),
        "registered_count": len(registeredTables),
    })
}

// 分页获取项目列表
func GetFormList(c *gin.Context) {
    currentUser := GetCurrentUser(c)
    if currentUser == nil {
        JsonResponse(c, http.StatusUnauthorized, "请先登录", nil)
        return
    }
	var query configs.FormQuery
	if err := c.ShouldBindJSON(&query); err != nil {
		JsonResponse(c, http.StatusBadRequest, "Invalid request parameters", nil)
		return
	}
    // 限制最大每页数量
    if query.PageSize > 300 {
        query.PageSize = 300
    }
	cx := configs.DB.Model(&configs.FormSchema{}).Order("id DESC")
	if currentUser.Role != "admin" {
	    cx.Where(configs.DB.Where("created_by", currentUser.ID).Or("JSON_CONTAINS(Tby, ?)", fmt.Sprintf("[%d]", currentUser.ID))) //这里Tby是json字段[1,2]
	}
	if query.Search != "" {
		cx.Where("formname LIKE ?", "%"+query.Search+"%")
	}
	var total int64
	var forms []configs.FormSchema
	cx.Count(&total).Scopes(configs.Paginate(query.Page, query.PageSize)).Find(&forms)
	JsonResponse(c, http.StatusOK, "获取成功", configs.FormListResponse{
		Items: forms,
		Total: total,
	})
}

// 获取项目属性
func GetFormSchema(id uint) (configs.FormSchema, error) {
	var bgsx configs.FormSchema
	if err := configs.DB.Where("id = ?", id).First(&bgsx).Error; err != nil {
		return configs.FormSchema{}, err
	}
	return bgsx, nil
}

// 创建项目
func CreateForm(c *gin.Context) {
    var form configs.FormSchema
    if err := c.ShouldBindJSON(&form); err != nil {
        fmt.Println(err)
        JsonResponse(c, http.StatusBadRequest, "Invalid request data", nil)
        return
    }
    validate := validator.New() //验证表单
    if err := validate.Struct(form); err != nil {
        for _, err := range err.(validator.ValidationErrors) {
            fmt.Println("Field:", err.Field(), "Error:", err.Tag())
        }
        JsonResponse(c, http.StatusBadRequest, "Validation failed", nil)
        return
    }
    // 获取用户信息
    currentUser := GetCurrentUser(c)
    if currentUser == nil {
        JsonResponse(c, http.StatusUnauthorized, "请先登录", nil)
        return
    }
    // 使用JWT中的用户ID生成表名
    form.TableName = configs.GeneratePhysicalTableName(form.FormName, fmt.Sprintf("%d", currentUser.ID))
    form.CreatedBy = currentUser.ID // 直接设置创建者ID
    // 校验字段配置
    if _, err := configs.ValidateFieldConfigs(form); err != nil {
        JsonResponse(c, http.StatusUnprocessableEntity, err.Error(), nil)
        return
    }
    // 校验预约类表单
    if err := configs.ValidateFormSchema(form); err != nil {
        JsonResponse(c, http.StatusUnprocessableEntity, err.Error(), nil)
        return
    }
    tx := configs.DB.Begin()
    defer func() {
        if r := recover(); r != nil {
            tx.Rollback()
        }
    }()
    if err := tx.Create(&form).Error; err != nil {
        tx.Rollback()
        JsonResponse(c, http.StatusConflict, "表单名称已存在", nil)
        return
    }
    if err := configs.CreatePhysicalTable(tx, form); err != nil {
        tx.Rollback()
        JsonResponse(c, http.StatusInternalServerError, "创建物理表失败", nil)
        return
    }
    // 检查并修改查询条件字段类型
    if err := configs.CheckAndUpdateFields(tx, form); err != nil {
        tx.Rollback()
        JsonResponse(c, http.StatusInternalServerError, err.Error(), nil)
        return
    }
    tx.Commit()
    go func() {
        configs.CreateMessage(nil, currentUser.ID, "创建项目成功", fmt.Sprintf("项目名称：%s，时间：%s", form.FormName, time.Now().Format("2006-01-02 15:04")))
    }()
    JsonResponse(c, http.StatusOK, "表单创建成功", form)
}

// 更新表单
func UpdateForm(c *gin.Context) {
    var data configs.FormSchema
    if err := c.ShouldBindJSON(&data); err != nil {
        JsonResponse(c, http.StatusBadRequest, "请求数据格式错误", err)
        return
    }
    // 获取用户信息
    currentUser := GetCurrentUser(c)
    if currentUser == nil {
        JsonResponse(c, http.StatusUnauthorized, "请先登录", nil)
        return
    }
    var existing configs.FormSchema
    if err := configs.DB.Where("id = ?", data.ID).First(&existing).Error; err != nil {
        JsonResponse(c, http.StatusNotFound, "查询不存在", nil)
        return
    }
    // 权限验证
    if currentUser.Role != "admin" && (currentUser.Role == "xmgly" && existing.CreatedBy != currentUser.ID) {
        JsonResponse(c, http.StatusForbidden, "项目管理员只能修改自己创建的项目", nil)
        return
    }
    // 校验字段配置
    if _, err := configs.ValidateFieldConfigs(data); err != nil {
        JsonResponse(c, http.StatusUnprocessableEntity, err.Error(), nil)
        return
    }
    // 校验预约类表单
    if err := configs.ValidateFormSchema(data); err != nil {
        JsonResponse(c, http.StatusUnprocessableEntity, err.Error(), nil)
        return
    }
    tx := configs.DB.Begin()
    defer func() {
        if r := recover(); r != nil {
            tx.Rollback()
        }
    }()
    // 先更新表单元数据
    if err := tx.Model(&configs.FormSchema{}).Where("id = ?", data.ID).Select("FormName", "Cxtj", "Kfcx", "Kftb", "Mhcx", "Sfbt", "Jghp", "Xsxh","Pxzd", "Glkz", "Dblc", "Qtxs", "Dblcxx", "Glcx", "Wytb", "Suoding", "Wordmb", "Fields", "TemplateID", "Reservation", "IsReservation", "EnableVerification", "Zsmb", "Remark", "Tby", "StartTime", "EndTime", "ProcessConfig", "ProcessActions").Updates(&data).Error; err != nil {
        tx.Rollback()
        JsonResponse(c, http.StatusInternalServerError, "更新失败", nil)
        return
    }
    data.TableName = existing.TableName
    // 检查并修改表结构
    if err := configs.CheckRules(tx, existing, data); err != nil {
        tx.Rollback()
        JsonResponse(c, http.StatusBadRequest, err.Error(), nil)
        return
    }
    // 检查并修改查询条件字段类型
    if err := configs.CheckAndUpdateFields(tx, data); err != nil {
        tx.Rollback()
        JsonResponse(c, http.StatusInternalServerError, err.Error(), nil)
        return
    }
    tx.Commit()
    go func() {
        configs.CreateMessage(nil, currentUser.ID, "修改项目成功", fmt.Sprintf("项目名称：%s，时间：%s", data.FormName, time.Now().Format("2006-01-02 15:04")))
    }()
    JsonResponse(c, http.StatusOK, "更新成功", data)
}

// 批量删除（集成级联删除和物理表清理）
func BatchDeleteForms(c *gin.Context) {
    var ids struct {
        IDs []uint `json:"ids" binding:"required,min=1"`
    }
    if err := c.ShouldBindJSON(&ids); err != nil {
        JsonResponse(c, http.StatusBadRequest, "无效的ID列表", nil)
        return
    }
    currentUser := GetCurrentUser(c)
    if currentUser == nil {
        JsonResponse(c, http.StatusUnauthorized, "请先登录", nil)
        return
    }
    err := configs.DB.Transaction(func(tx *gorm.DB) error {
        // 1. 预加载需要删除的关联数据
        var forms []configs.FormSchema
        if err := tx.Preload("ProcessInstances.ApprovalRecords").Where("id IN ?", ids.IDs).Find(&forms).Error; err != nil {
            return err
        }
        // 2. 收集需要删除的物理表名
        tables := make([]string, 0, len(forms))
        for _, form := range forms {
            tables = append(tables, form.TableName)
        }
        // 3. 级联删除主体数据（使用 Select(clause.Associations)）
        if err := tx.Select(clause.Associations).Delete(&forms).Error; err != nil {
            return fmt.Errorf("删除表单元数据失败: %v", err)
        }
        // 4. 删除物理表（在同一个事务中）
        for _, table := range tables {
            if err := tx.Exec(fmt.Sprintf("DROP TABLE IF EXISTS `%s`", table)).Error; err != nil {
                return fmt.Errorf("删除物理表 %s 失败: %v", table, err)
            }
        }
        return nil
    })
    if err != nil {
        JsonResponse(c, http.StatusInternalServerError, "删除失败: "+err.Error(), nil)
        return
    }
    // 5. 异步记录日志（确保在事务提交后执行）
    go func(ids []uint, userID uint) {
        idStrings := make([]string, len(ids))
        for i, id := range ids {
            idStrings[i] = strconv.FormatUint(uint64(id), 10)
        }
        configs.CreateMessage(nil, userID, "批量删除项目",fmt.Sprintf("删除数量：%d，ID：%s，时间：%s",len(ids),strings.Join(idStrings, ","),time.Now().Format("2006-01-02 15:04")))
    }(ids.IDs, currentUser.ID)
    JsonResponse(c, http.StatusOK, "删除成功", nil)
}

//批量插入数据
func Tablepost(c *gin.Context) {
    // 获取传递过来的数据
    var requestData struct {
        TableName string                  `json:"tablename"` // 表名
        Data      []map[string]interface{} `json:"data"`      // 数据
    }

    // 绑定请求数据
    if err := c.ShouldBindJSON(&requestData); err != nil {
        JsonResponse(c, http.StatusBadRequest, "无效的数据格式: "+err.Error(), nil)
        return
    }
    
    // 获取当前用户ID
    user := GetCurrentUser(c)
    if user == nil {
        JsonResponse(c, http.StatusUnauthorized, "用户未登录", nil)
        return
    }
    
    // 遍历数据，添加cjz字段
    for i := range requestData.Data {
        row := requestData.Data[i]
        row["cjz"] = user.ID
    }

    // 1. 校验数据格式
    if len(requestData.Data) == 0 {
        JsonResponse(c, http.StatusBadRequest, "没有提供数据进行插入", nil)
        return
    }

    // 2. 转换数据类型为 []interface{}
    var interfaceData []interface{}
    for _, row := range requestData.Data {
        interfaceData = append(interfaceData, row)
    }

    // 3. 直接插入数据
    err := insertBatchData(requestData.TableName, interfaceData)
    if err != nil {
        JsonResponse(c, http.StatusInternalServerError, "插入数据失败: "+err.Error(), nil)
        return
    }

    // 插入完成后返回成功响应
    JsonResponse(c, http.StatusOK, fmt.Sprintf("成功插入 %d 条数据到表 %s", len(requestData.Data), requestData.TableName), nil)
}

// insertBatchData 动态插入数据
func insertBatchData(tableName string, data []interface{}) error {
    if len(data) == 0 {
        return nil
    }

    // 获取字段名，并按字母顺序排序以确保一致性
    keys := make([]string, 0)
    firstRow, ok := data[0].(map[string]interface{})
    if !ok {
        return fmt.Errorf("无效的数据类型")
    }
    for key := range firstRow {
        keys = append(keys, key)
    }
    sort.Strings(keys) // 排序以确保字段顺序一致

    // 检查所有数据行是否具有相同的字段
    for _, row := range data {
        rowMap, ok := row.(map[string]interface{})
        if !ok {
            return fmt.Errorf("无效的数据类型")
        }
        if len(rowMap) != len(keys) {
            return fmt.Errorf("数据字段数量不一致")
        }
        for _, key := range keys {
            if _, exists := rowMap[key]; !exists {
                return fmt.Errorf("缺失字段 %s", key)
            }
        }
    }

    // 构建 SQL 语句占位符部分
    placeholders := make([]string, len(data))
    for i := range data {
        // 生成正确数量的 ? 占位符并用逗号分隔
        qMarks := strings.TrimSuffix(strings.Repeat("?, ", len(keys)), ", ")
        placeholders[i] = fmt.Sprintf("(%s)", qMarks)
    }

    // 构建完整的 SQL 插入语句
    query := fmt.Sprintf(
        "INSERT INTO %s (%s) VALUES %s",
        tableName,
        strings.Join(keys, ", "),
        strings.Join(placeholders, ", "),
    )

    // 构造插入数据的值（按排序后的 keys 顺序）
    valuesToInsert := make([]interface{}, 0)
    for _, row := range data {
        rowMap := row.(map[string]interface{})
        for _, key := range keys {
            valuesToInsert = append(valuesToInsert, rowMap[key])
        }
    }

    // 输出调试信息
    // fmt.Printf("Generated Query: %s\n", query)
    // fmt.Printf("Values to Insert: %v\n", valuesToInsert)

    // 执行 SQL 插入
    return configs.DB.Exec(query, valuesToInsert...).Error
}